/**
 * 日期处理辅助类
 * 基于Day.js封装统一的日期处理方法，支持MobX状态管理
 */

// 引入Day.js
import dayjs from 'dayjs';

// 内联插件代码，避免导入问题
const relativeTimePlugin = function (option, Dayjs, dayjs) {
  dayjs.prototype.fromNow = function (withoutSuffix) {
    return this.from(dayjs(), withoutSuffix);
  };
  dayjs.prototype.from = function (compared, withoutSuffix) {
    const target = (compared instanceof Dayjs) ? compared : dayjs(compared);
    const diff = this.diff(target, 'millisecond');
    const seconds = Math.abs(diff) / 1000;
    const minutes = seconds / 60;
    const hours = minutes / 60;
    const days = hours / 24;
    const months = days / 30;
    const years = months / 12;

    const result = seconds < 45 ? '几秒' :
      seconds < 90 ? '1分钟' :
      minutes < 45 ? Math.round(minutes) + '分钟' :
      minutes < 90 ? '1小时' :
      hours < 24 ? Math.round(hours) + '小时' :
      hours < 48 ? '1天' :
      days < 30 ? Math.round(days) + '天' :
      days < 60 ? '1个月' :
      days < 365 ? Math.round(months) + '个月' :
      years < 2 ? '1年' :
      Math.round(years) + '年';

    return withoutSuffix ? result : (diff > 0 ? result + '后' : result + '前');
  };
};

const isBetweenPlugin = function (option, Dayjs, dayjs) {
  dayjs.prototype.isBetween = function (a, b, unit, inclusivity = '()') {
    const first = dayjs(a);
    const last = dayjs(b);
    const include = inclusivity || '()';
    const start = include[0] === '(' ? this.isAfter(first, unit) : this.isSameOrAfter(first, unit);
    const end = include[1] === ')' ? this.isBefore(last, unit) : this.isSameOrBefore(last, unit);
    return start && end;
  };
};

const isSameOrBeforePlugin = function (option, Dayjs, dayjs) {
  dayjs.prototype.isSameOrBefore = function (date, unit) {
    return this.isSame(date, unit) || this.isBefore(date, unit);
  };
};

const isSameOrAfterPlugin = function (option, Dayjs, dayjs) {
  dayjs.prototype.isSameOrAfter = function (date, unit) {
    return this.isSame(date, unit) || this.isAfter(date, unit);
  };
};

const calendarPlugin = function (option, Dayjs, dayjs) {
  dayjs.prototype.calendar = function (referenceDay) {
    const formatStr = {
      sameDay: '[今天] HH:mm',
      nextDay: '[明天] HH:mm',
      nextWeek: '[下周]dddd HH:mm',
      lastDay: '[昨天] HH:mm',
      lastWeek: '[上周]dddd HH:mm',
      sameElse: 'YYYY-MM-DD HH:mm'
    };
    return this.format(formatStr[this.calendar$calendarFormat(referenceDay || dayjs())]);
  };
  
  dayjs.prototype.calendar$calendarFormat = function (refDay) {
    const day = this.startOf('day');
    const refDayStart = refDay.startOf('day');
    const nextDayStart = refDayStart.add(1, 'day');
    const nextWeekStart = refDayStart.add(7, 'day');
    
    if (day.isSame(refDayStart)) return 'sameDay';
    if (day.isSame(nextDayStart)) return 'nextDay';
    if (day.isBefore(nextWeekStart)) return 'nextWeek';
    
    const lastDayStart = refDayStart.subtract(1, 'day');
    const lastWeekStart = refDayStart.subtract(7, 'day');
    
    if (day.isSame(lastDayStart)) return 'lastDay';
    if (day.isAfter(lastWeekStart)) return 'lastWeek';
    
    return 'sameElse';
  };
};

// 注册插件
dayjs.extend(relativeTimePlugin);
dayjs.extend(isBetweenPlugin);
dayjs.extend(isSameOrBeforePlugin);
dayjs.extend(isSameOrAfterPlugin);
dayjs.extend(calendarPlugin);

// 设置中文语言
dayjs.locale('zh-cn', {
  months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
  monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
  weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
  weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
  weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
  formats: {
    LT: 'HH:mm',
    LTS: 'HH:mm:ss',
    L: 'YYYY/MM/DD',
    LL: 'YYYY年M月D日',
    LLL: 'YYYY年M月D日 HH:mm',
    LLLL: 'YYYY年M月D日dddd HH:mm'
  },
  relativeTime: {
    future: '%s内',
    past: '%s前',
    s: '几秒',
    m: '1分钟',
    mm: '%d分钟',
    h: '1小时',
    hh: '%d小时',
    d: '1天',
    dd: '%d天',
    M: '1个月',
    MM: '%d个月',
    y: '1年',
    yy: '%d年'
  }
});

/**
 * 日期辅助工具类
 * 提供日期格式化和计算相关的方法，支持MobX的计算属性
 */
export const dateHelper = {
  /**
   * 获取Day.js实例
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {Object} Day.js实例
   */
  dayjs(date) {
    return dayjs(date);
  },
  
  /**
   * 格式化日期
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @param {String} format 格式化模板
   * @returns {String} 格式化后的日期字符串
   */
  format(date, format = 'YYYY-MM-DD HH:mm:ss') {
    if (!date) return '';
    return dayjs(date).format(format);
  },
  
  /**
   * 格式化为日期
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {String} 格式化后的日期字符串 (YYYY-MM-DD)
   */
  formatDate(date) {
    return this.format(date, 'YYYY-MM-DD');
  },
  
  /**
   * 格式化为时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {String} 格式化后的时间字符串 (HH:mm:ss)
   */
  formatTime(date) {
    return this.format(date, 'HH:mm:ss');
  },
  
  /**
   * 格式化为日期和时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {String} 格式化后的日期时间字符串 (YYYY-MM-DD HH:mm)
   */
  formatDateTime(date) {
    return this.format(date, 'YYYY-MM-DD HH:mm');
  },
  
  /**
   * 格式化为中文日期
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @param {Boolean} withTime 是否包含时间
   * @returns {String} 格式化后的中文日期字符串
   */
  formatCN(date, withTime = false) {
    if (!date) return '';
    if (withTime) {
      return this.format(date, 'YYYY年MM月DD日 HH:mm:ss');
    }
    return this.format(date, 'YYYY年MM月DD日');
  },
  
  /**
   * 格式化为友好的时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {String} 格式化后的友好时间字符串
   */
  formatFriendly(date) {
    if (!date) return '';
    
    const now = dayjs();
    const target = dayjs(date);
    const diffDays = now.diff(target, 'day');
    
    if (diffDays === 0) {
      return '今天 ' + target.format('HH:mm');
    } else if (diffDays === 1) {
      return '昨天 ' + target.format('HH:mm');
    } else if (diffDays === 2) {
      return '前天 ' + target.format('HH:mm');
    } else if (diffDays <= 7) {
      return target.format('dddd HH:mm');
    } else if (target.year() === now.year()) {
      return target.format('MM-DD HH:mm');
    } else {
      return target.format('YYYY-MM-DD HH:mm');
    }
  },
  
  /**
   * 获取相对时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @returns {String} 相对时间字符串
   */
  timeAgo(date) {
    if (!date) return '';
    // 如果是数字且位数小于13，视为秒级时间戳
    if (typeof date === 'number' && date < 10000000000) {
      date = date * 1000;
    }
    return dayjs(date).fromNow();
  },
  
  /**
   * 计算两个日期之间的差异
   * @param {Date|String|Number} date1 第一个日期
   * @param {Date|String|Number} date2 第二个日期
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Number} 差异值
   */
  diff(date1, date2, unit = 'day') {
    if (!date1 || !date2) return 0;
    return dayjs(date1).diff(dayjs(date2), unit);
  },
  
  /**
   * 判断日期是否在另一个日期之前
   * @param {Date|String|Number} date1 第一个日期
   * @param {Date|String|Number} date2 第二个日期
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Boolean} 是否在之前
   */
  isBefore(date1, date2, unit = 'day') {
    if (!date1 || !date2) return false;
    return dayjs(date1).isBefore(dayjs(date2), unit);
  },
  
  /**
   * 判断日期是否在另一个日期之后
   * @param {Date|String|Number} date1 第一个日期
   * @param {Date|String|Number} date2 第二个日期
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Boolean} 是否在之后
   */
  isAfter(date1, date2, unit = 'day') {
    if (!date1 || !date2) return false;
    return dayjs(date1).isAfter(dayjs(date2), unit);
  },
  
  /**
   * 判断日期是否与另一个日期相同
   * @param {Date|String|Number} date1 第一个日期
   * @param {Date|String|Number} date2 第二个日期
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Boolean} 是否相同
   */
  isSame(date1, date2, unit = 'day') {
    if (!date1 || !date2) return false;
    return dayjs(date1).isSame(dayjs(date2), unit);
  },
  
  /**
   * 判断日期是否在指定范围内
   * @param {Date|String|Number} date 日期
   * @param {Date|String|Number} start 开始日期
   * @param {Date|String|Number} end 结束日期
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Boolean} 是否在范围内
   */
  isBetween(date, start, end, unit = 'day') {
    if (!date || !start || !end) return false;
    return dayjs(date).isBetween(dayjs(start), dayjs(end), unit, '[]');
  },
  
  /**
   * 获取当前时间戳(毫秒)
   * @returns {Number} 当前时间戳
   */
  now() {
    return dayjs().valueOf();
  },
  
  /**
   * 获取当前时间戳(秒)
   * @returns {Number} 当前时间戳(秒)
   */
  timestamp() {
    return Math.floor(dayjs().valueOf() / 1000);
  },
  
  /**
   * 获取今天的开始时间
   * @returns {Number} 今天开始的时间戳
   */
  startOfToday() {
    return dayjs().startOf('day').valueOf();
  },
  
  /**
   * 获取今天的结束时间
   * @returns {Number} 今天结束的时间戳
   */
  endOfToday() {
    return dayjs().endOf('day').valueOf();
  },
  
  /**
   * 获取本周的开始时间
   * @returns {Number} 本周开始的时间戳
   */
  startOfWeek() {
    return dayjs().startOf('week').valueOf();
  },
  
  /**
   * 获取本周的结束时间
   * @returns {Number} 本周结束的时间戳
   */
  endOfWeek() {
    return dayjs().endOf('week').valueOf();
  },
  
  /**
   * 获取本月的开始时间
   * @returns {Number} 本月开始的时间戳
   */
  startOfMonth() {
    return dayjs().startOf('month').valueOf();
  },
  
  /**
   * 获取本月的结束时间
   * @returns {Number} 本月结束的时间戳
   */
  endOfMonth() {
    return dayjs().endOf('month').valueOf();
  },
  
  /**
   * 添加时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @param {Number} amount 添加的数量
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Date} 添加后的日期对象
   */
  add(date, amount, unit = 'day') {
    return dayjs(date).add(amount, unit).toDate();
  },
  
  /**
   * 减去时间
   * @param {Date|String|Number} date 日期对象、日期字符串或时间戳
   * @param {Number} amount 减去的数量
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Date} 减去后的日期对象
   */
  subtract(date, amount, unit = 'day') {
    return dayjs(date).subtract(amount, unit).toDate();
  },
  
  /**
   * 解析字符串为日期对象
   * @param {String} dateString 日期字符串
   * @param {String} format 格式
   * @returns {Date} 日期对象
   */
  parse(dateString, format) {
    if (format) {
      return dayjs(dateString, format).toDate();
    }
    return dayjs(dateString).toDate();
  },
  
  // === MobX 计算属性相关方法 ===
  
  /**
   * 创建日期格式化计算属性
   * @param {Function} dateSelector 从Store中选择日期的函数
   * @param {String} format 格式化模板
   * @returns {Function} 计算属性函数
   */
  createFormatter(dateSelector, format = 'YYYY-MM-DD HH:mm:ss') {
    return function() {
      const date = dateSelector(this);
      return date ? dayjs(date).format(format) : '';
    };
  },
  
  /**
   * 创建相对时间计算属性
   * @param {Function} dateSelector 从Store中选择日期的函数
   * @returns {Function} 计算属性函数
   */
  createTimeAgo(dateSelector) {
    return function() {
      const date = dateSelector(this);
      return date ? dayjs(date).fromNow() : '';
    };
  },
  
  /**
   * 创建友好时间计算属性
   * @param {Function} dateSelector 从Store中选择日期的函数
   * @returns {Function} 计算属性函数
   */
  createFriendlyTime(dateSelector) {
    return function() {
      const date = dateSelector(this);
      return dateHelper.formatFriendly(date);
    };
  },
  
  /**
   * 创建日期比较计算属性
   * @param {Function} date1Selector 第一个日期选择器
   * @param {Function} date2Selector 第二个日期选择器
   * @param {String} compareType 比较类型 ('before', 'after', 'same')
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Function} 计算属性函数
   */
  createDateComparer(date1Selector, date2Selector, compareType = 'before', unit = 'day') {
    return function() {
      const date1 = date1Selector(this);
      const date2 = date2Selector(this);
      
      if (!date1 || !date2) return false;
      
      const d1 = dayjs(date1);
      const d2 = dayjs(date2);
      
      switch(compareType) {
        case 'before':
          return d1.isBefore(d2, unit);
        case 'after':
          return d1.isAfter(d2, unit);
        case 'same':
          return d1.isSame(d2, unit);
        default:
          return false;
      }
    };
  },
  
  /**
   * 创建日期范围检查计算属性
   * @param {Function} dateSelector 日期选择器
   * @param {Function} startSelector 开始日期选择器
   * @param {Function} endSelector 结束日期选择器
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Function} 计算属性函数
   */
  createDateRangeChecker(dateSelector, startSelector, endSelector, unit = 'day') {
    return function() {
      const date = dateSelector(this);
      const start = startSelector(this);
      const end = endSelector(this);
      
      if (!date || !start || !end) return false;
      
      return dayjs(date).isBetween(dayjs(start), dayjs(end), unit, '[]');
    };
  },
  
  /**
   * 创建剩余时间计算属性
   * @param {Function} dateSelector 日期选择器
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Function} 计算属性函数
   */
  createRemainingTime(dateSelector, unit = 'day') {
    return function() {
      const date = dateSelector(this);
      if (!date) return 0;
      
      const diff = dayjs(date).diff(dayjs(), unit);
      return diff > 0 ? diff : 0;
    };
  },
  
  /**
   * 创建已过时间计算属性
   * @param {Function} dateSelector 日期选择器
   * @param {String} unit 单位 (year, month, week, day, hour, minute, second)
   * @returns {Function} 计算属性函数
   */
  createElapsedTime(dateSelector, unit = 'day') {
    return function() {
      const date = dateSelector(this);
      if (!date) return 0;
      
      const diff = dayjs().diff(dayjs(date), unit);
      return diff > 0 ? diff : 0;
    };
  },
  
  /**
   * 创建状态计算属性 (过期、即将到期、正常)
   * @param {Function} dateSelector 日期选择器
   * @param {Number} warningDays 警告天数
   * @returns {Function} 计算属性函数
   */
  createDeadlineStatus(dateSelector, warningDays = 3) {
    return function() {
      const date = dateSelector(this);
      if (!date) return 'normal';
      
      const diff = dayjs(date).diff(dayjs(), 'day');
      
      if (diff < 0) return 'expired';
      if (diff <= warningDays) return 'warning';
      return 'normal';
    };
  },
  
  /**
   * 创建日历文本计算属性
   * @param {Function} dateSelector 日期选择器
   * @returns {Function} 计算属性函数
   */
  createCalendarText(dateSelector) {
    return function() {
      const date = dateSelector(this);
      if (!date) return '';
      
      return dayjs(date).calendar();
    };
  },
  
  /**
   * 将数组中的日期字段格式化
   * @param {Array} array 数组
   * @param {String|Array} fields 要格式化的字段
   * @param {String} format 格式化模板
   * @returns {Array} 格式化后的数组
   */
  formatArrayDates(array, fields, format = 'YYYY-MM-DD HH:mm') {
    if (!array || !array.length) return [];
    
    const fieldList = Array.isArray(fields) ? fields : [fields];
    
    return array.map(item => {
      const newItem = { ...item };
      
      fieldList.forEach(field => {
        if (newItem[field]) {
          newItem[`${field}Formatted`] = this.format(newItem[field], format);
        }
      });
      
      return newItem;
    });
  }
}; 